﻿using LogNet6;

using System.Collections.Concurrent;

namespace MPNet6.Server.Demo.Models;
internal class LoggerProcessor : ILoggerProcessor, IDisposable
{
    private readonly BlockingCollection<LoggerPara> _MessageQueue = new();

    private readonly SqlConnection _CN;
    private readonly SqlCommand _Cmd;

    private readonly Thread _OutputThread;


    public LoggerProcessor(string connectionString)
    {
        _CN = new SqlConnection(connectionString);
        _Cmd = _CN.CreateCommand();
        _Cmd.CommandText = $"INSERT INTO Logs (ProjectName,Dt,Name,LogLevel,Msg) VALUES ('MessagePush',@Dt,@Name,@LogLevel,@Msg)";
        _Cmd.Parameters.Add(new SqlParameter("@Name", System.Data.SqlDbType.NVarChar, 256));
        _Cmd.Parameters.Add(new SqlParameter("@LogLevel", System.Data.SqlDbType.NVarChar, 16));
        _Cmd.Parameters.Add(new SqlParameter("@Msg", System.Data.SqlDbType.NVarChar, int.MaxValue));
        _Cmd.Parameters.Add(new SqlParameter("@Dt", System.Data.SqlDbType.DateTime));

        // Start Console message queue processor
        _OutputThread = new Thread(ProcessLogQueue)
        {
            IsBackground = true,
            Name = "Logger queue processing thread"
        };
        _OutputThread.Start();
    }
    private void WriteMessage(LoggerPara p)
    {
        try
        {
            _Cmd.Parameters[0].Value = $"{p.CategoryName}[{p.EventId.Id}]";
            _Cmd.Parameters[1].Value = p.LogLevel.ToString();
            _Cmd.Parameters[2].Value = p.Message;
            _Cmd.Parameters[3].Value = p.DateTime;

            if (_CN.State == System.Data.ConnectionState.Closed)
                _CN.Open();
            _Cmd.ExecuteNonQuery();
        }
        catch(Exception  )
        {
        }
    }
    private void ProcessLogQueue()
    {
        while (!_MessageQueue.IsCompleted)
        {
            try
            {
                WriteMessage(_MessageQueue.Take());
                if (_MessageQueue.Count == 0)
                    _CN.Close();
            }
            catch
            {
                break;
            }
        }
    }


    public void AddLog(LoggerPara message)
    {
        if (_MessageQueue.IsAddingCompleted)
            WriteMessage(message);
        else
            _MessageQueue.Add(message);

    }



    public void Dispose()
    {
        _MessageQueue.CompleteAdding();
        try
        {
            _OutputThread.Join(1500); // with timeout in-case Console is locked by user input
        }
        catch (ThreadStateException) { }

        _CN.Close();
    }


}